package com.immediatus.graphics.texture.bitmap;

import android.graphics.Bitmap;
import android.graphics.Bitmap.Config;
import android.opengl.GLUtils;
import com.immediatus.graphics.contracts.IBitmapTextureAtlasSource;
import com.immediatus.graphics.texture.TextureAtlas;
import com.immediatus.graphics.texture.TextureOptions;
import com.immediatus.graphics.util.BitmapTextureFormat;
import com.immediatus.graphics.util.OpenGLWrapper;

import javax.microedition.khronos.opengles.GL10;
import java.util.ArrayList;


public class BitmapTextureAtlas extends TextureAtlas<IBitmapTextureAtlasSource>{

    private BitmapTextureFormat _bitmapTextureFormat;

    public BitmapTextureAtlas(final int width_, final int height_){
        this(width_, height_, BitmapTextureFormat.RGBA_8888);
    }

    public BitmapTextureAtlas(final int width_, final int height_, final BitmapTextureFormat bitmapTextureFormat_){
        this(width_, height_, bitmapTextureFormat_, TextureOptions.DEFAULT, null);
    }

    public BitmapTextureAtlas(final int width_, final int height_, final ITextureAtlasStateListener<IBitmapTextureAtlasSource> textureAtlasStateListener_){
        this(width_, height_, BitmapTextureFormat.RGBA_8888, TextureOptions.DEFAULT, textureAtlasStateListener_);
    }

    public BitmapTextureAtlas(final int width_, final int height_, final BitmapTextureFormat bitmapTextureFormat_, final ITextureAtlasStateListener<IBitmapTextureAtlasSource> textureAtlasStateListener_){
        this(width_, height_, bitmapTextureFormat_, TextureOptions.DEFAULT, textureAtlasStateListener_);
    }

    public BitmapTextureAtlas(final int width_, final int height_, final TextureOptions textureOptions_) throws IllegalArgumentException{
        this(width_, height_, BitmapTextureFormat.RGBA_8888, textureOptions_, null);
    }

    public BitmapTextureAtlas(final int width_, final int height_, final BitmapTextureFormat bitmapTextureFormat_, final TextureOptions textureOptions_) throws IllegalArgumentException{
        this(width_, height_, bitmapTextureFormat_, textureOptions_, null);
    }

    public BitmapTextureAtlas(final int width_, final int height_, final TextureOptions textureOptions_, final ITextureAtlasStateListener<IBitmapTextureAtlasSource> textureAtlasStateListener_) throws IllegalArgumentException{
        this(width_, height_, BitmapTextureFormat.RGBA_8888, textureOptions_, textureAtlasStateListener_);
    }

    public BitmapTextureAtlas(final int width_, final int height_, final BitmapTextureFormat bitmapTextureFormat_, final TextureOptions textureOptions_, final ITextureAtlasStateListener<IBitmapTextureAtlasSource> textureAtlasStateListener_) throws IllegalArgumentException{
        super(width_, height_, bitmapTextureFormat_.getPixelFormat(), textureOptions_, textureAtlasStateListener_);

        this._bitmapTextureFormat = bitmapTextureFormat_;
    }

    public BitmapTextureFormat getBitmapTextureFormat(){
        return this._bitmapTextureFormat;
    }

    @Override
    protected void writeTextureToHardware(final GL10 gl_){
        final Config bitmapConfig = this._bitmapTextureFormat.getBitmapConfig();
        final int glFormat = this._PixelFormat.getGLFormat();
        final int glType = this._PixelFormat.getGLType();
        final boolean preMultipyAlpha = this._TextureOptions._PreMultipyAlpha;
        final ArrayList<IBitmapTextureAtlasSource> textureSources = this.getTextureAtlasSources();

        for (final IBitmapTextureAtlasSource bitmapTextureAtlasSource : textureSources){
            if (bitmapTextureAtlasSource != null){
                final Bitmap bitmap = bitmapTextureAtlasSource.onLoadBitmap(bitmapConfig);
                try{
                    if (bitmap == null){
                        throw new IllegalArgumentException(bitmapTextureAtlasSource.getClass().getSimpleName() + ": " + bitmapTextureAtlasSource.toString() + " returned a null Bitmap.");
                    }
                    if (preMultipyAlpha){
                        GLUtils.texSubImage2D(GL10.GL_TEXTURE_2D, 0, bitmapTextureAtlasSource.getTexturePositionX(), bitmapTextureAtlasSource.getTexturePositionY(), bitmap, glFormat, glType);
                    } else{
                        OpenGLWrapper.glTexSubImage2D(gl_, GL10.GL_TEXTURE_2D, 0, bitmapTextureAtlasSource.getTexturePositionX(), bitmapTextureAtlasSource.getTexturePositionY(), bitmap, this._PixelFormat);
                    }

                    bitmap.recycle();
                } catch (final IllegalArgumentException iae){
                    if (this.getTextureStateListener() != null){
                        this.getTextureStateListener().onTextureAtlasSourceLoadExeption(this, bitmapTextureAtlasSource, iae);
                    } else{
                        throw iae;
                    }
                }
            }
        }
    }

    @Override
    protected void bindTextureOnHardware(final GL10 gl_){
        super.bindTextureOnHardware(gl_);

        final PixelFormat pixelFormat = this._bitmapTextureFormat.getPixelFormat();
        final int glFormat = pixelFormat.getGLFormat();
        final int glType = pixelFormat.getGLType();
        gl_.glTexImage2D(GL10.GL_TEXTURE_2D, 0, glFormat, this.getWidth(), this.getHeight(), 0, glFormat, glType, null);
    }
}
